﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace IslandUnit.Providers
{
    /// <summary>
    /// Base class for mock framework providers
    /// </summary>
    public abstract class MockProviderBase
    {
        /// <summary>
        /// Creates the mock object.
        /// </summary>
        /// <typeparam name="TDependency">The type of the dependency.</typeparam>
        /// <returns>The mock object</returns>
        public abstract object CreateMockObject<TDependency>() where TDependency : class;

        /// <summary>
        /// Setup the return of the stub.
        /// </summary>
        /// <typeparam name="TDependency">The type of the dependency.</typeparam>
        /// <typeparam name="TResult">The type of object returned.</typeparam>
        /// <typeparam name="TException">The type of exception to throw.</typeparam>
        /// <param name="mock">The mock object</param>
        /// <param name="method">The target function of the stub.</param>
        public abstract void MockThrowException<TDependency, TResult, TException>(object mock, Expression<Func<TDependency, TResult>> method) 
            where TDependency : class 
            where TException : Exception, new();

        /// <summary>
        /// Setup the return of the stub.
        /// </summary>
        /// <typeparam name="TDependency">The type of the dependency.</typeparam>
        /// <typeparam name="TResult">The type of object returned.</typeparam>
        /// <typeparam name="TException">The type of exception to throw.</typeparam>
        /// <param name="mock">The mock object</param>
        /// <param name="method">The target function of the stub.</param>
        public abstract void MockThrowException<TDependency, TResult, TException>(object mock, Expression<Func<TDependency, IList<TResult>>> method)
            where TDependency : class
            where TException : Exception, new();

        /// <summary>
        /// Setup the return of the stub.
        /// </summary>
        /// <typeparam name="TDependency">The type of the dependency.</typeparam>
        /// <typeparam name="TResult">The type of object returned.</typeparam>
        /// <typeparam name="TException">The type of exception to throw.</typeparam>
        /// <param name="mock">The mock object</param>
        /// <param name="method">The target function of the stub.</param>
        public abstract void MockThrowException<TDependency, TResult, TException>(object mock, Expression<Func<TDependency, IEnumerable<TResult>>> method)
            where TDependency : class
            where TException : Exception, new();

        /// <summary>
        /// Setup the return of the stub.
        /// </summary>
        /// <typeparam name="TDependency">The type of the dependency.</typeparam>
        /// <typeparam name="TResult">The type of object returned.</typeparam>
        /// <param name="mock">The mock object</param>
        /// <param name="method">The target function of the stub.</param>
        /// <param name="objectToReturn">The object to return.</param>
        public abstract void MockReturn<TDependency, TResult>(object mock, Expression<Func<TDependency, TResult>> method, TResult objectToReturn) 
            where TDependency : class;

        /// <summary>
        /// Setup the return of the stub.
        /// </summary>
        /// <typeparam name="TDependency">The type of the dependency.</typeparam>
        /// <typeparam name="TResult">The type of object returned.</typeparam>
        /// <param name="mock">The mock object</param>
        /// <param name="method">The target function of the stub.</param>
        /// <param name="objectToReturn">The object to return.</param>
        public abstract void MockReturn<TDependency, TResult>(object mock, Expression<Func<TDependency, IList<TResult>>> method, IList<TResult> objectToReturn) 
            where TDependency : class;

        /// <summary>
        /// Setup the return of the stub.
        /// </summary>
        /// <typeparam name="TDependency">The type of the dependency.</typeparam>
        /// <typeparam name="TResult">The type of object returned.</typeparam>
        /// <param name="mock">The mock object</param>
        /// <param name="method">The target function of the stub.</param>
        /// <param name="objectToReturn">The object to return.</param>
        public abstract void MockReturn<TDependency, TResult>(object mock, Expression<Func<TDependency, IEnumerable<TResult>>> method, IEnumerable<TResult> objectToReturn) 
            where TDependency : class;

        /// <summary>
        /// Gets the mocked object.
        /// </summary>
        /// <typeparam name="TDependency">The type of the dependency.</typeparam>
        /// <param name="mock">The mock object.</param>
        /// <returns>The mocked object</returns>
        public abstract TDependency GetMockObject<TDependency>(object mock) 
            where TDependency : class;

        /// <summary>
        /// Verifies all the mock expectations setted up in the mocked object.
        /// </summary>
        /// <typeparam name="TDependency">The type of the dependency.</typeparam>
        /// <param name="mockSetups">The mock setups.</param>
        public abstract void VerifyMockExpectations<TDependency>(IEnumerable<MockSetup<TDependency>> mockSetups) 
            where TDependency : class;

        /// <summary>
        /// Creates an placeholder for a method parameter.
        /// </summary>
        /// <typeparam name="TParameter">The type of the parameter.</typeparam>
        /// <returns>The placeholder for a method parameter.</returns>
        public abstract TParameter MethodParameter<TParameter>();
    }

}